package alingrad.engine.graphics;

import alingrad.engine.objects.TreeNode;

public class Animation extends TreeNode {

	public static final int TYPE_DEFAULT = 0;
	public static final int TYPE_BACKFORTH = 1;

	private final int mFrameStart;
	private final int mFrameEnd;

	private int mFrameDelay;

	public int mFrame;
	private int mCurrentFrameTime;
	private int mFrameDirection;

	private int mAnimType;
	private boolean mRepeat;
	private boolean mIsDone;

	/**
	 * Constructs a new Animation that contains the initial data.
	 * @param frameStart The index of the first frame of the animation in the sprite array.
	 * @param frameEnd The index of the last frame of the animation in the sprite array.
	 * @param frameDelay The delay (in milliseconds) between each frame.
	 */
	public Animation(final int frameStart, final int frameEnd, final int frameDelay) {
		mFrameStart = frameStart;
		mFrameEnd = frameEnd;
		mFrameDelay = frameDelay;
		mAnimType = TYPE_DEFAULT;
		mRepeat = true;
		mIsDone = false;
	}

	/**
	 * Sets the Animation type.
	 * @param animType the animation type.
	 */
	public void setType(final int animType) {
		mAnimType = animType;
	}

	/**
	 * Resets the animation to its initial state.
	 */
	public void reset() {
		mFrame = mFrameStart;
		mIsDone = false;
		mCurrentFrameTime = 0;
		if (mAnimType == TYPE_BACKFORTH)
			mFrameDirection = 1;
	}

	/**
	 * Updates the animation to decide whether or not it needs to swap frames.
	 * @param delta time in milliseconds since the last update.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */
	public void update(final long delta) {
		if (!mIsDone) {
			mCurrentFrameTime += delta;
			if (mCurrentFrameTime < mFrameDelay)
				return;
			if (mAnimType == TYPE_DEFAULT)
				updateFrame();
			else //if (animType == TYPE_BACKFORTH)
				updateFrameBackForth();
		}
	}

	/**
	 * Updates the animation to the correct frame if the type is equalt to {@link #TYPE_DEFAULT}.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */
	public void updateFrame() {
		int frameDelta = 0;
		while (mCurrentFrameTime > mFrameDelay) {
			mCurrentFrameTime -= mFrameDelay;
			frameDelta++;
		}
		while (frameDelta > 0) {
			frameDelta--;
			mFrame++;
			if (mRepeat) {
				if (mFrame > mFrameEnd)
					mFrame = mFrameStart;
			}else {
				mFrame = mFrameEnd;
				mIsDone = true;
			}
		}
	}

	/**
	 * Updates the animation to the correct frame if the type is equal to {@link #TYPE_BACKFORTH}.
	 * @return the index of the current frame in the sprite array which needs to be drawn.
	 */

	private void updateFrameBackForth() {
		int frameDelta = 0;
		while (mCurrentFrameTime > mFrameDelay) {
			mCurrentFrameTime -= mFrameDelay;
			frameDelta++;
		}
		while (frameDelta > 0) {
			frameDelta--;
			mFrame += mFrameDirection;
			if (mFrameDirection > 0) {
				if (mFrame > mFrameEnd) {
					mFrameDirection = -1;
					mFrame = mFrameEnd - 1;
				}
			}
			else {
				if (mFrame < mFrameStart) {
					if (mRepeat) {
						mFrameDirection = 1;
						mFrame = mFrameStart + 1;
					}else {
						mFrame = mFrameStart;
						mIsDone = true;
					}
				}
			}
		}
	}
}
